package core;

import core.myersDiff.MyersDiff;
import core.myersDiff.PathNode;
import fileoperation.FileReader;
import gitobject.Blob;
import gitobject.Commit;
import gitobject.GitObject;
import gitobject.Tree;
import repository.Repository;
import stage.Index;
import utils.setOperation;

import java.io.File;
import java.io.IOException;
import java.util.*;

import static core.JitReset.getAllBlob;

public class JitDiff {

    /**
     * compare the difference between index and repository
     * @throws Exception
     */
    public static void compareCache() throws Exception {
        HashMap<String, String> indexFiles = Index.getIndexMap();
        HashMap<String, String> repoFiles = new HashMap<>();
        HashSet<String> newFiles;
        HashSet<String> newFiles_r;

        if (Commit.getLastCommit() != null) {
            Commit lastCommit = Commit.deserialize(Commit.getLastCommit());
            repoFiles = getAllBlob(lastCommit.getTree());
        }
        newFiles_r = setOperation.getDifference(repoFiles, indexFiles);
        newFiles = setOperation.getDifference(indexFiles, repoFiles);
        if (!newFiles.isEmpty()) {
            int i = 0;
            String[] filenames = new String[newFiles.size()];
            String[] filehash1 = new String[newFiles.size()];
            for (String hash : newFiles_r) {
                filenames[i] = repoFiles.get(hash);
                filehash1[i] = hash;
                i++;
            }
            for (int j = 0; j < Index.indexFileList.size(); j++) {
                for (int k = 0; k < newFiles_r.size(); k++) {
                    if (Index.indexFileList.get(j)[2].equals(filenames[k])) {
                        Blob blob = Blob.deserialize(Index.indexFileList.get(j)[1]);
                        Blob blob1 = Blob.deserialize(filehash1[k]);
                        System.out.println("diff --git" + "\s" + "a/" + Index.indexFileList.get(j)[2] + "\s" +
                                "b/" + filenames[k]);
                        System.out.println("index " + Index.indexFileList.get(j)[1].substring(0, 6) + ".." +
                                filehash1[k].substring(0, 6) + "\s" + "100644");
                        System.out.println("--- a/" + Index.indexFileList.get(j)[2]);
                        System.out.println("+++ b/" + filenames[k]);
                        compareFileStr(blob1.getValue(), blob.getValue());

                    }
                }
            }
        } else {
            System.out.println("There is no difference between index and repository");
        }
    }

    /**
     * compare two files, return the changes
     * @param before
     * @param after
     * @throws IOException
     */
    public static void compareFile(File before, File after) throws IOException {
        String befStr = new String(GitObject.getValue(before));
        String aftStr = new String(GitObject.getValue(after));
        System.out.println("diff --git" + "\s" + "a/" + before.getName() + "\s" +
                "b/" + after.getName());
        System.out.println("--- a/" + before.getName());
        System.out.println("+++ b/" + after.getName());
        compareFileStr(befStr, aftStr);
    }

    /**
     * compare two string, return the changes
     * @param befStr
     * @param aftStr
     * @throws IOException
     */
    public static void compareFileStr(String befStr, String aftStr) throws IOException {
        List<String> befVal = FileReader.readByBufferReader(befStr);
        List<String> aftVal = FileReader.readByBufferReader(aftStr);

        MyersDiff<String> myersDiff = new MyersDiff<>();
        try {
            PathNode pathNode = myersDiff.buildPath(befVal, aftVal);
            List<String> result =  myersDiff.buildDiff(pathNode, befVal, aftVal);

            myersDiff.printDiff(result,befVal,aftVal);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * compare files in two commits, return the changes
     * @param commitID1
     * @param commitID2
     * @throws IOException
     */
    public static void compareCommit(String commitID1, String commitID2) throws IOException {
        HashSet<String> newFiles = new HashSet<>();
        HashSet<String> newFiles1 = new HashSet<>();

        HashMap<String, String> commitFiles1 = new HashMap<>();
        Commit commit1 = Commit.deserialize(commitID1);
        commitFiles1 = getAllBlob(commit1.getTree());

        HashMap<String, String> commitFiles2 = new HashMap<>();
        Commit commit2 = Commit.deserialize(commitID2);
        commitFiles2 = getAllBlob(commit2.getTree());

        newFiles = setOperation.getDifference(commitFiles1, commitFiles2);
        newFiles1 = setOperation.getDifference(commitFiles2, commitFiles1);
        if (!newFiles.isEmpty()) {
            int i = 0;
            int m = 0;
            String[] filenames1 = new String[newFiles.size()];
            String[] filehash1 = new String[newFiles.size()];
            String[] filenames2 = new String[newFiles1.size()];
            String[] filehash2 = new String[newFiles1.size()];
            for (String hash : newFiles) {
                filenames1[i] = commitFiles1.get(hash);
                filehash1[i] = hash;
                i++;
            }
            for (String hash : newFiles1) {
                filenames2[m] = commitFiles2.get(hash);
                filehash2[m] = hash;
                m++;
            }

            for (int j = 0; j < newFiles1.size(); j++) {
                for (int k = 0; k < newFiles.size(); k++) {
                    if (filenames2[j].equals(filenames1[k])) {
                        Blob blob = Blob.deserialize(filehash2[j]);
                        Blob blob1 = Blob.deserialize(filehash1[k]);
                        System.out.println("diff --git" + "\s" + "a/" + filenames2[j] + "\s" +
                                "b/" + filenames1[k]);
                        System.out.println("index " + filehash2[j].substring(0, 6) + ".." +
                                filehash1[k].substring(0, 6) + "\s" + "100644");
                        System.out.println("--- a/" + filenames2[j]);
                        System.out.println("+++ b/" + filenames1[k]);
                        compareFileStr(blob1.getValue(), blob.getValue());
                    }
                }
            }
        }else {
            System.out.println("There is no difference between these branches");
        }
    }

    /**
     * record additions and deletions between two files
     * @param before
     * @param after
     * @return
     * @throws Exception
     */
    public static List<String> fileChange(File before, File after) throws Exception {
        String befStr = GitObject.getValue(before);
        String aftStr = GitObject.getValue(after);
        List<String> befVal = FileReader.readByBufferReader(befStr);
        List<String> aftVal = FileReader.readByBufferReader(aftStr);
        MyersDiff<String> myersDiff = new MyersDiff<>();
        PathNode pathNode = myersDiff.buildPath(befVal, aftVal);
        List<String> result =  myersDiff.buildDiff(pathNode, befVal, aftVal);
        return myersDiff.getChange(result);
    }

    /**
     * record additions and deletions between two strings
     * @param befStr
     * @param aftStr
     * @return
     * @throws Exception
     */
    public static List<String> strChange(String befStr, String aftStr) throws Exception {
        List<String> befVal = FileReader.readByBufferReader(befStr);
        List<String> aftVal = FileReader.readByBufferReader(aftStr);
        MyersDiff<String> myersDiff = new MyersDiff<>();
        PathNode pathNode = myersDiff.buildPath(befVal, aftVal);
        List<String> result =  myersDiff.buildDiff(pathNode, befVal, aftVal);
        return myersDiff.getChange(result);
    }
}
